#include "Object.h"
#include <stdexcept>
using namespace RayTrace;
using namespace std;
Object::Object(void):textured(false)
{
}

Object::~Object(void)
{

}

RayTrace::Object::FaceIterator::FaceIterator( Object * pObj ):mObject(pObj),mMatFaceIndex(0),mSubFaceIndex(0)
{
	
}

RayTrace::Object::FaceIterator::FaceIterator():mObject(0),mMatFaceIndex(0),mSubFaceIndex(0)
{
	
}
RayTrace::Object::FaceIterator::~FaceIterator( void )
{
	mObject=NULL;
}

void RayTrace::Object::FaceIterator::first()
{
	mMatFaceIndex=0;
	mSubFaceIndex=0;
}


void RayTrace::Object::FaceIterator::next()
{
	if (!isDone())
	{
		MaterialFaces& matface=mObject->MatFaces[mMatFaceIndex];
		if (++mSubFaceIndex>=matface.subFaces.size())
		{
			++mMatFaceIndex;
			mSubFaceIndex=0;
		}
	}
}

size_t RayTrace::Object::FaceIterator::materialIndex()
{
	if (!isDone())
	{
		return mObject->MatFaces[mMatFaceIndex].MatIndex;
	}
	else
	{
		throw range_error("index material error!");
	}
}

bool RayTrace::Object::FaceIterator::isDone()
{
	return mMatFaceIndex>=mObject->MatFaces.size();
}

const Face& RayTrace::Object::FaceIterator::face()
{
	size_t faceIndex=mObject->MatFaces[mMatFaceIndex].subFaces[mSubFaceIndex];
	return mObject->Faces[faceIndex];
}

void RayTrace::Object::FaceIterator::initial( Object * pObj )
{
	mObject=pObj;
}

RayTrace::CTriangle RayTrace::Object::FaceIterator::triangle()
{
	return mObject->GetTriangleFromFace(face());
}

RayTrace::vector3 RayTrace::Object::FaceIterator::GetNormalFromBarycentric( const vector3& barycentric )
{
	return mObject->GetNormalFromBarycentric(this->face(),barycentric);
}
RayTrace::CTriangle RayTrace::Object::GetTriangleFromFace( const Face & face ) const
{
	return CTriangle(Vertices[face.v1],Vertices[face.v2],Vertices[face.v3]);
}

RayTrace::vector3 RayTrace::Object::GetNormalFromBarycentric( const Face & face ,const vector3& barycentric) const
{
	return Normals[face.v1]*barycentric.x+Normals[face.v2]*barycentric.y+Normals[face.v3]*barycentric.z;
}

void RayTrace::Object::GenBoundingBox()
{
	aabb.maxx=aabb.maxy=aabb.maxz=-MMAX;
	aabb.minx=aabb.miny=aabb.minz=MMAX;
	
	for (size_t i=0;i<Vertices.size();++i)
	{
		const vector3& v3=Vertices[i];
		if (v3.x>aabb.maxx)	aabb.maxx=v3.x;
		if (v3.x<aabb.minx) aabb.minx=v3.x;

		if (v3.y>aabb.maxy)	aabb.maxy=v3.y;
		if (v3.y<aabb.miny) aabb.miny=v3.y;

		if (v3.z>aabb.maxz)	aabb.maxz=v3.z;
		if (v3.z<aabb.minz) aabb.minz=v3.z;
	}
}

bool RayTrace::Object::IsIntersect( const Ray& ray )
{
	return aabb.IsIntersect(ray);
}

void RayTrace::Object::GenKdtree()
{
	kdtree.Init(this);
}

double RayTrace::Object::Intersect(const Ray& ray,int& faceindex)
{
	return kdtree.IntersectRay(ray,faceindex);
}

bool RayTrace::Object::FaceIterator::operator==(const FaceIterator& faceit) const
{
	return (mObject==faceit.mObject && 
		mMatFaceIndex==faceit.mMatFaceIndex &&
		mSubFaceIndex==faceit.mSubFaceIndex);
}